package old.resourceCache;


import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.zip.ZipEntry;


import utilities.SimpleHashMap;
import utilities.MapEntry;

public class ResCache {
	
	public LinkedList<ResHandle> resHandleList; //may have to synchronize for thread safe
	public SimpleHashMap<ZipEntry, ResHandle> resHandleMap; //may have to synchronize for thread safe
		
	private int cacheSize;
	private int allocated;
	private IResourceFile file;	
	
	public ResCache(int sizeInMb, IResourceFile resFile)
	{
	        cacheSize = sizeInMb * 1024 * 1024;//total memory size
	        allocated = 0; // total memory allocated
	        file = resFile;
	}
	
	//Destructor listed in C++ code, may be necessary here (p.196)
	

	//retrieve handle from map using resource name
	public ResHandle getHandle(ZipEntry entry) {
		
		//Return handle based on resource name
		ResHandle handle = resHandleMap.get(entry);
				
		//Finish
		if(handle == null)
			handle = load(entry);
		else
			update(handle);
		
		
		return handle;
	}
	
	//load resource not already in cache
	private ResHandle load(ZipEntry entry) {
		int size = (int) file.getResourceSize(entry);
		char[] buffer = allocate(size);
		
		if(buffer == null)
		{
			return null;
		}
		
		ZipEntry ze = new ZipEntry(entry);//(name);		
		ResHandle handle = new ResHandle(ze, buffer, size, this);//r.createHandle(buffer, size, this);
		handle.load(file);
		resHandleList.push(handle);
		resHandleMap.put(ze, handle);
		
		return handle;		
	}
	
	//allocate memory in cache (if possible)
	private char[] allocate(int size) 
	{
		if(!makeRoom(size))
			return null;
		
		char[] mem = new char[size];  //Differs from online code--doublecheck this
		
		if (mem!=null)
		{
			allocated += size;
		}
		
		return mem;
	}

	
	private boolean makeRoom(int size) {
		
		if (size > cacheSize)
		{
			return false;
		}
		
		while (size > (cacheSize - allocated))
		{
			if (resHandleList.isEmpty())
				return false;
			
			freeOneResource();
		}
		return true;
	}

	//remove resources from cache to make room for new resource
	private void freeOneResource() {
		
		//ListIterator gonner = resHandleList.listIterator(resHandleList.size());// gonner = resHandleList.getLast();
		//gonner.previous();
		
		ResHandle handle = resHandleList.peekLast();
		
		resHandleList.pop();
		resHandleMap.remove(handle.getResource().getName());
		allocated -= handle.getSize();
		//m_allocated -= handle->m_resource.m_size ;
        //delete handle;
        // This is where the reshandle should be freed....
		
	}

	//remove handle from list, promote to front of list
	private void update(ResHandle handle) 
	{
		resHandleList.remove(handle);
		resHandleList.push(handle);
	}
	
	//locate resHandle given a resource name (NOTE:  May change to pass in a resource,
	//then extract name from resource to get key into map)
	private ResHandle find(ZipEntry entry)
	{
		ResHandle handle = resHandleMap.get(entry);
		return handle;  //returns null if not found in resHandleMap		
	}
	
	private void flush()
	{
		//TBD		
	}
	
	//find resource by handle, remove from the cache
	private void free(ResHandle handle)
	{
		resHandleList.remove(handle);
		resHandleMap.remove(handle.getResource());
	}
	
	private void memoryHasBeenFreed(int size)
	{
		allocated -= size;
	}
}
